package pdf;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Erstellt die Trainingspläne als
 * PDF-Dokumente
 *
 * Kopfzeile angelehnt an
 * http://itextpdf.com/examples/iia.php?id=118
 * 
 * @author felix
 */
public class PdfServlet extends HttpServlet {
    /** 
     * Verarbeitet die HTTP <code>GET</code> Methode
     * @author felix
     * @param request Servletanfrage
     * @param response Servletantwort
     * @throws ServletException wenn ein servletspezifischer Fehler auftritt
     * @throws IOException wenn ein I/O Fehler auftritt
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        doPost(request, response);
    } 

     /**
     * Erstellt eine Tabeller in der Kopfzeile
     * mit "Seite x von y"
     * @author felix
     * @param x seitenzahl
     * @param y gesamtseitenzahl
     * @return Tabelle für Kopfzeile
     */
    public static PdfPTable getHeaderTable(int x, int y) {
        // Neue Tabelle mit 3 Spalten und einer Breite von 523 anlegen
        PdfPTable table = new PdfPTable(3);
        table.setTotalWidth(523);
        table.setLockedWidth(true);

        // Linke Spalte mit Überschrift
        table.getDefaultCell().setFixedHeight(35);
        table.getDefaultCell().setBorder(Rectangle.BOTTOM);
        table.getDefaultCell().setVerticalAlignment(Element.ALIGN_BOTTOM);
        table.addCell("Trainingsplan");

        // Mittlere Spalte mit Seitenzahk
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
        table.getDefaultCell().setVerticalAlignment(Element.ALIGN_BOTTOM);
        table.addCell(String.format("Seite %d von %d", x, y));

        // Rechte Spalte mit Werbung
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.getDefaultCell().setVerticalAlignment(Element.ALIGN_BOTTOM);
        table.addCell(String.format("TMA.pheelix.com"));
        return table;
    }

    /** 
     * Verarbeitet die HTTP <code>POST</code> Methode
     * @author felix
     * @param request Servletanfrage
     * @param response Servletantwort
     * @throws ServletException wenn ein servletspezifischer Fehler auftritt
     * @throws IOException wenn ein I/O Fehler auftritt
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {        

        // design initialisieren
        String design = null;

        // Teste ob Parameter design übergeben würde
        if(request.getParameterMap().containsKey("design")){
            // Setze design mit Parameter design
            design = request.getParameter("design");
        }

        // Neues A4 Dokument mit genug Abstand vom Rand für Kopfzeile erstellen
        Document document = new Document(PageSize.A4, 36, 36, 60, 36);

        try{
            // Ausgabetyp auf pdf setzen
            response.setContentType("application/pdf");

            // Ausgabedateinamen festlegen
            response.setHeader("Content-Disposition"," attachment; filename=\"trainingplan.pdf\"");

            // Outputstream starten
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            // PDFWriter-Instanz für Dokument starten
            PdfWriter.getInstance(document, baos);

            // Dokument öffnen
            document.open();

            // Erste Seite öffnen
            document.newPage();

            // Trainingsplan anhand Parameter id laden
            String[][] trainingplan = db.trainingplans.getTrainingplanById(request.getParameter("id"));

            // Alle Übungen für einen Trainingsplan laden
            String[][] trainingplanexercises = db.trainingplanexercises.getTraingplanExercisesByTrainingplanId(trainingplan[0][0]);

            // Übersichtstabelle mit 4 Spalten, 100% Breite und jeweils 25% breiten Spalten anlegen
            PdfPTable summaryTable = new PdfPTable(7);
            summaryTable.setWidthPercentage(100);
            summaryTable.setWidths(new int[]{5,1,5,1,5,1,5});
            summaryTable.setSpacingBefore(5);
            summaryTable.setSpacingAfter(5);

            // Neue Zelle anlegen
            PdfPCell cell;
            Integer lineCount = 1;

            // Wenn das normale Design ist
            if(!design.equals("mini")){
                // Neue Zelle mit der Bezeichnugn des Trainingsplans anlegen
                cell = new PdfPCell(new Phrase(new Chunk(trainingplan[0][1],new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD))));
                cell.setColspan(4);
                cell.setBackgroundColor(BaseColor.LIGHT_GRAY);
                cell.setBorder(0);
                cell.setFixedHeight(20);

                // Zelle zur Tabelle hinzufügen
                summaryTable.addCell(cell);

                // Zelle mit Dauer und Datum hinzufügen
                cell = new PdfPCell(new Phrase(db.exercises.getExercisesDuration(trainingplanexercises) + " Minuten, " + trainingplan[0][2]));
                cell.setBorder(0);
                cell.setColspan(3);
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                cell.setBackgroundColor(BaseColor.LIGHT_GRAY);
                summaryTable.addCell(cell);

                // Zelle vor der Übungsübersicht
                cell = new PdfPCell(new Phrase(new Chunk("Übungen:",new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD))));
                cell.setBorder(0);

                summaryTable.addCell(cell);

                Integer columnCount = 1;
                Integer columnHelper = 0;

                // Für jede Übung des Plans, schreibe den Namen und eine fortlaufende Nummer in eine Zelle
                for(String[] trainingplanexercise: trainingplanexercises){
                    if(columnCount == 3){
                        cell = new PdfPCell(new Phrase(lineCount + ". "));
                        cell.setBorder(0);
                        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                        summaryTable.addCell(cell);
                        
                        cell = new PdfPCell(new Phrase(db.exercises.getName(trainingplanexercise[0])));
                        cell.setBorder(0);
                        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                        summaryTable.addCell(cell);

                        columnCount = 1;
                        columnHelper = 1;
                    } else if(columnHelper == 1){
                        cell = new PdfPCell(new Phrase(" "));
                        cell.setBorder(0);
                        summaryTable.addCell(cell);

                        cell = new PdfPCell(new Phrase(lineCount + ". "));
                        cell.setBorder(0);
                        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                        summaryTable.addCell(cell);

                        cell = new PdfPCell(new Phrase(db.exercises.getName(trainingplanexercise[0])));
                        cell.setBorder(0);
                        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                        summaryTable.addCell(cell);

                        columnCount++;
                        columnHelper = 0;
                    } else {
                        cell = new PdfPCell(new Phrase(lineCount + ". "));
                        cell.setBorder(0);
                        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                        summaryTable.addCell(cell);

                        cell = new PdfPCell(new Phrase(db.exercises.getName(trainingplanexercise[0])));
                        cell.setBorder(0);
                        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                        summaryTable.addCell(cell);
                        columnCount++;
                    }

                    lineCount++;
                }

                // Fülle leere Zellen auf um Tabelle zu komplettieren
                if(columnCount == 2){
                    cell = new PdfPCell(new Phrase(" "));
                    cell.setBorder(0);
                    summaryTable.addCell(cell);
                    
                    cell = new PdfPCell(new Phrase(" "));
                    cell.setBorder(0);
                    summaryTable.addCell(cell);

                    cell = new PdfPCell(new Phrase(" "));
                    cell.setBorder(0);
                    summaryTable.addCell(cell);

                    cell = new PdfPCell(new Phrase(" "));
                    cell.setBorder(0);
                    summaryTable.addCell(cell);
                } else if (columnCount == 3){
                    cell = new PdfPCell(new Phrase(" "));
                    cell.setBorder(0);
                    summaryTable.addCell(cell);

                    cell = new PdfPCell(new Phrase(" "));
                    cell.setBorder(0);
                    summaryTable.addCell(cell);
                }
            }

            // Übersichtstabelle in Dokument platzieren
            document.add(summaryTable);

            lineCount = 1;

            // Für jede Übung des Trainingsplans ...
            for(String[] trainingplanexercise: trainingplanexercises){
                // Starte neue Tabelle mit zwei Spalten
                PdfPTable exerciseTable = new PdfPTable(2);

                // Trenne Tabelle bei Seitenumbruch nicht
                exerciseTable.setKeepTogether(true);
                exerciseTable.setWidthPercentage(100);

                // Bei minimalem Design ...
                if(design.equals("mini")){
                    // 10% Breite für Bilderspalte
                    exerciseTable.setWidths(new int[]{8,2});
                } else {
                    // 30% Breite für Bilderspalte
                    exerciseTable.setWidths(new int[]{7,3});
                }
                exerciseTable.setSpacingBefore(5);
                exerciseTable.setSpacingAfter(5);

                // Graue Zelle mit Namen der Übung
                cell = new PdfPCell(new Phrase(new Chunk(lineCount + ". Übung: " + db.exercises.getName(trainingplanexercise[0]),new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD))));
                cell.setColspan(2);
                cell.setFixedHeight(20);
                cell.setBorder(0);
                cell.setBackgroundColor(BaseColor.LIGHT_GRAY);

                // Zelle zur Tabelle hinzufügen
                exerciseTable.addCell(cell);

                // Übungsdetails laden
                String[] exercise = db.exercises.getExerciseDetailsByExerciseId(trainingplanexercise[0]);

                Phrase phrase = new Phrase();

                // Wenn es das minimale Design ist ...
                if(design.equals("mini")){
                    // Zeige nur den Ablauf
                    phrase.add(new Chunk("Ablauf:\n", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
                    phrase.add(new Chunk(exercise[2] + "\n", new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL)));
                } else {
                    // Baue Inhalt mit Ziel, Dauer, Ablauf, Hinweise, Aufbau und Hilfsmitteln
                    phrase.add(new Chunk("Ziel:\n", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
                    phrase.add(new Chunk(exercise[9] + "\n", new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL)));
                    phrase.add(new Chunk("Dauer: ", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
                    phrase.add(new Chunk(exercise[8] + " Minuten\n", new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL)));

                    /** Teilnehmer interessiert hier nicht mehr ...
                     *
                     phrase.add(new Chunk("Teilnehmer: ", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
                    phrase.add(new Chunk(exercise[4] + " bis " + exercise[5] + "\n", new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL)));
                     */

                    if(!exercise[2].equals("")){
                        phrase.add(new Chunk("Ablauf:\n", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
                        phrase.add(new Chunk(exercise[2] + "\n", new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL)));
                    }
                    if(!exercise[3].equals("")){
                        phrase.add(new Chunk("Hinweise:\n", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
                        phrase.add(new Chunk(exercise[3] + "\n", new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL)));
                    }
                    if(!exercise[6].equals("")){
                        phrase.add(new Chunk("Aufbau:\n", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
                        phrase.add(new Chunk(exercise[6] + "\n", new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL)));
                    }
                    if(!exercise[7].equals("")){
                        phrase.add(new Chunk("Hilfsmittel:\n", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
                        phrase.add(new Chunk(exercise[7] + "\n", new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL)));
                    }
                }

                // Inhalt in Zelle schreiben
                cell = new PdfPCell(phrase);
                cell.setBorder(0);

                // Zelle zur Tabelle hinzufügen
                exerciseTable.addCell(cell);

                // Bilder der Übung laden
                String[][] images =  db.pictures.getAllPicturesByExerciseId(exercise[1]);

                // Wenn ein Bild gefunden wurde
                if(images.length > 0){
                    // Für jedes Bild
                    for(String image[]: images){
                        // Baue Pfad zum Bild
                        String relativeWebPath = "pict/exercise/" + image[3];
                        String absoluteDiskPath = getServletContext().getRealPath(relativeWebPath);
                        Image imghead = Image.getInstance(absoluteDiskPath);
                        
                        // Neue Zelle mit Bild als Inhalt
                        cell = new PdfPCell(imghead, true);
                        cell.setBorder(0);
                        cell.setHorizontalAlignment(Element.ALIGN_RIGHT);

                        // Zelle zur Tabelle hinzufügen
                        exerciseTable.addCell(cell);
                    }
                } else {
                     // Wenn kein Bild gefunden wurde, schreibe Hinweis aus
                     cell = new PdfPCell(new Phrase("Kein Bild vorhanden"));
                     cell.setBorder(0);
                     cell.setHorizontalAlignment(Element.ALIGN_RIGHT);

                     // Zelle zur Tabelle hinzufügen
                     exerciseTable.addCell(cell);
                }
               
                lineCount++;

                // Tabelle zum Dokument hinzufügen
                document.add(exerciseTable);
            }

            // Dokument schließen
            document.close();

            // Nachdem das Dokument fertig ist, füge nachträglich
            // Kopfzeilen hinzu

            // Neuen PDFReader mit dem alten Outputstream anlegen
            PdfReader reader = new PdfReader(baos.toByteArray());
            
            // Stempel für den reader anlegen
            PdfStamper stamper = new PdfStamper(reader, response.getOutputStream());
            
            // Seitenanzahl auslesen
            Integer n = reader.getNumberOfPages();

            // Für jede Seite ...
            for (Integer i = 1; i <= n; i++) {
                // Erstelle die Kopfzeile und platziere die Tabelle im Kopf
                getHeaderTable(i, n).writeSelectedRows(0, -1, 36, 823,stamper.getOverContent(i));
            }
            // Schließe den Stempel
            stamper.close();
        } catch (DocumentException ex) {
            Logger.getLogger(PdfServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}